package com.oxymore.jbnetapi.connectors;

import java.net.URL;
import java.util.HashMap;
import java.util.Map;

import com.oxymore.jbnetapi.core.ApiException;
import com.oxymore.jbnetapi.core.ApiPage;
import com.oxymore.jbnetapi.core.ApiPath;
import com.oxymore.jbnetapi.core.ApiRegion;
import com.oxymore.jbnetapi.core.ApiRequest;
import com.oxymore.jbnetapi.wow.auction.AuctionDump;
import com.oxymore.jbnetapi.wow.character.Profile;
import com.oxymore.jbnetapi.wow.constants.ApiArenaTeamSize;
import com.oxymore.jbnetapi.wow.guild.Guild;
import com.oxymore.jbnetapi.wow.item.Item;
import com.oxymore.jbnetapi.wow.pvp.Arena;
import com.oxymore.jbnetapi.wow.realm.Realms;

/**
 * The World of Warcraft API connector, it's used to query the Bnet WoW API, see
 * further documentation.
 * 
 * @author Valentin
 * 
 */
public class WoWApiConnector extends AbstractConnector
{
	private static WoWApiConnector instance;

	public static WoWApiConnector getInstance(String baseUrl,
			String privateKey, String publicKey)
	{
		if (instance == null)
			instance = new WoWApiConnector(baseUrl, privateKey, publicKey);
		if (privateKey == null || publicKey == null)
			instance.isUsingAuth = false;
		else
			instance.isUsingAuth = true;
		return instance;
	}

	public static WoWApiConnector getInstance(String baseUrl)
	{
		return getInstance(baseUrl, null, null);
	}

	/**
	 * @param baseUrl
	 *            the baseurl of your bnet's region {@link ApiRegion}
	 * @param privateKey
	 *            your API private key, given by Blizzard
	 * @param publicKey
	 *            your API public key, given by Blizzard
	 */
	private WoWApiConnector(String baseUrl, String privateKey, String publicKey)
	{
		super(baseUrl, privateKey, publicKey);
	}

	/**
	 * Return the status of all realms if no parameters are passed or the status
	 * of the specified realm(s)
	 * 
	 * @param realmList
	 *            a string representing a list of realms coma separated eg:
	 *            "medivh,chogall"
	 * @return a {@link Realms} instance containing the result of your request
	 * @throws Exception
	 */
	public Realms getRealmsStatus(String realmList) throws ApiException
	{
		Map<String, String> params = new HashMap<String, String>();
		params.put("realms", realmList);
		final ApiRequest request = new ApiRequest(ApiPath.REALM,
				ApiPage.REALM_STATUS, params);
		final URL requestUrl = getURL(request);
		final String authString = buildAuthorization(requestUrl.getPath());
		Realms result = gson.fromJson(getContent(requestUrl, authString),
				Realms.class);
		if (result == null)
			throw new ApiException("Empty response", requestUrl.toString());
		if (result.getStatus() != null && result.getStatus().equals("nok"))
			throw new ApiException(result.getStatus(), result.getReason(),
					requestUrl.toString());
		return result;
	}

	/**
	 * 
	 * @param realmSlug
	 *            the slug of the targeted character realm
	 * @param charName
	 *            the target character name
	 * @param optionnalFields
	 *            a string representing the list of additionnal information you
	 *            wish to get for the target character
	 * @return a {@link Profile} instance containing the result of your request
	 * @throws Exception
	 */
	public Profile getChararacterProfile(String realmSlug, String charName,
			String optionnalFields) throws ApiException
	{
		Map<String, String> params = new HashMap<String, String>();
		params.put("fields", optionnalFields);
		final ApiRequest request = new ApiRequest(ApiPath.CHARACTER,
				ApiPage.NONE, "/" + realmSlug + "/" + charName, params);
		final URL requestUrl = getURL(request);
		final String authString = buildAuthorization(requestUrl.getPath());
		Profile result = gson.fromJson(getContent(requestUrl, authString),
				Profile.class);
		if (result == null)
			throw new ApiException("Empty response", requestUrl.toString());
		if (result.getStatus() != null && result.getStatus().equals("nok"))
			throw new ApiException(result.getStatus(), result.getReason(),
					requestUrl.toString());
		return result;
	}

	/**
	 * 
	 * @param realmSlug
	 *            the slug of the targeted arena team realm
	 * @param teamSize
	 *            the size of the targeted team @see {@link ApiArenaTeamSize}
	 * @param teamName
	 *            the name of the targeted team
	 * @return a {@link Arena} instance containing the result of your request
	 * @throws Exception
	 */
	public Arena getArenaTeamInfo(String realmSlug, String teamSize,
			String teamName) throws ApiException
	{
		final ApiRequest request = new ApiRequest(ApiPath.ARENA, ApiPage.NONE,
				"/" + realmSlug + "/" + teamSize + "/" + teamName);
		final URL requestUrl = getURL(request);
		final String authString = buildAuthorization(requestUrl.getPath());
		Arena result = gson.fromJson(getContent(requestUrl, authString),
				Arena.class);
		if (result == null)
			throw new ApiException("Empty response", requestUrl.toString());
		if (result.getStatus() != null && result.getStatus().equals("nok"))
			throw new ApiException(result.getStatus(), result.getReason(),
					requestUrl.toString());
		return result;
	}

	/**
	 * 
	 * @param itemId
	 *            the id of the targeted item
	 * @return a {@link Item} instance containing the result of your request
	 * @throws Exception
	 */
	public Item getItemInfo(Integer itemId) throws ApiException
	{
		final ApiRequest request = new ApiRequest(ApiPath.ITEM, ApiPage.NONE,
				"/" + itemId.toString());
		final URL requestUrl = getURL(request);
		final String authString = buildAuthorization(requestUrl.getPath());
		Item result = gson.fromJson(getContent(requestUrl, authString),
				Item.class);
		if (result == null)
			throw new ApiException("", requestUrl.toString());
		if (result.getStatus() != null && result.getStatus().equals("nok"))
			throw new ApiException(result.getStatus(), result.getReason(),
					requestUrl.toString());
		return result;
	}

	/**
	 * 
	 * @param realmSlug
	 *            the slug of the targeted guild's realm
	 * @param guildName
	 *            the name of the targeted guild
	 * @param optionnalFields
	 *            a string representing the list of additionnal information you
	 *            wish to get on the targeted guild, coma separated
	 * @return a {@link Guild} instance containing the result of your request
	 * @throws Exception
	 */
	public Guild getGuildProfile(String realmSlug, String guildName,
			String optionnalFields) throws ApiException
	{
		Map<String, String> params = new HashMap<String, String>();
		params.put("fields", optionnalFields);
		final ApiRequest request = new ApiRequest(ApiPath.GUILD, ApiPage.NONE,
				"/" + realmSlug + "/" + guildName, params);
		final URL requestUrl = getURL(request);
		final String authString = buildAuthorization(requestUrl.getPath());
		Guild result = gson.fromJson(getContent(requestUrl, authString),
				Guild.class);
		if (result == null)
			throw new ApiException("Empty response", requestUrl.toString());
		if (result.getStatus() != null && result.getStatus().equals("nok"))
			throw new ApiException(result.getStatus(), result.getReason(),
					requestUrl.toString());
		return result;
	}

	/**
	 * @param realmSlug
	 *            the slug of the targeted realm
	 * @return a {@link AuctionDump} instance containing the result of your
	 *         request
	 * @throws Exception
	 */
	public AuctionDump getRealmAuctionDump(String realmSlug)
			throws ApiException
	{
		final ApiRequest request = new ApiRequest(ApiPath.AUCTION_DUMP,
				ApiPage.NONE, "/" + realmSlug + "/auctions.json");
		final URL requestUrl = getURL(request);
		final String authString = buildAuthorization(requestUrl.getPath());
		AuctionDump result = gson.fromJson(getContent(requestUrl, authString),
				AuctionDump.class);
		if (result == null)
			throw new ApiException("Empty response", requestUrl.toString());
		if (result.getStatus() != null && result.getStatus().equals("nok"))
			throw new ApiException(result.getStatus(), result.getReason(),
					requestUrl.toString());
		return result;
	}
}
